package com.jing.android.notes.ui.widget;

import android.animation.ObjectAnimator;
import android.graphics.Color;
import android.text.TextPaint;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;

import androidx.appcompat.widget.AppCompatTextView;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.viewpager.widget.ViewPager;

/**
 * 不适用自定义View实现,是考虑每次切换tab,自定义View需要绘制所有的tab,用组装的方式只需要绘制需要更新的组件
 * 由于设计规范要求,事先知道container的width,根据这个宽度计算各个tab的宽度
 * <p>
 * 测试数据:
 * vIndicator.x默认值为0.0,vIndicator的滑动根据起点到终点之间的距离进行百分比(onPageScrolled的参数positionOffset)滑动
 * ViewPager.SCROLL_STATE_SETTLING表示已经确认最终要显示的页面,如果position发生变化,会调用onPageSelected,然后接着调用onPageScrolled滑动至最终页面
 * 从index到(index+1),onPageScrolled的参数positionOffset从小变大
 * 从index到(index-1),onPageScrolled的参数positionOffset从大变小，
 * <p>
 * 手势滑动的滑动周期
 * onPageScrollStateChanged -> ViewPager.SCROLL_STATE_DRAGGING
 * onPageScrolled -> 滑动
 * onPageScrollStateChanged -> ViewPager.SCROLL_STATE_SETTLING 确认最终要显示的页面,此时ViewPager.getCurrentItem已经是最终的位置
 * onPageScrolled -> 滑动至最终要显示的页面
 * onPageScrollStateChanged -> ViewPager.SCROLL_STATE_IDLE
 * <p>
 * ViewPager.setCurrentItem(position, true)
 * onPageScrollStateChanged -> ViewPager.SCROLL_STATE_SETTLING 确认最终要显示的页面,此时ViewPager.getCurrentItem已经是最终的位置
 * onPageSelected-> position
 * onPageScrolled -> 滑动至最终要显示的页面
 * onPageScrollStateChanged -> ViewPager.SCROLL_STATE_IDLE
 * <p>
 * ViewPager.setCurrentItem(position, false)
 * onPageSelected-> position
 * onPageScrolled position: position, 0.0
 * <p>
 * 快速滑动多个页面
 * onPageScrollStateChanged -> ViewPager.SCROLL_STATE_DRAGGING
 * onPageScrolled -> 滑动
 * onPageScrollStateChanged -> ViewPager.SCROLL_STATE_SETTLING 确认最终要显示的页面,此时ViewPager.getCurrentItem已经是最终的位置
 * onPageScrolled -> 滑动至最终要显示的页面
 * onPageScrollStateChanged -> ViewPager.SCROLL_STATE_DRAGGING
 * onPageScrolled -> 滑动
 * onPageScrollStateChanged -> ViewPager.SCROLL_STATE_SETTLING
 * onPageScrolled -> 滑动至最终要显示的页面
 * onPageScrollStateChanged -> ViewPager.SCROLL_STATE_IDLE
 *
 * @author JingTuo
 */
public class TabsController implements View.OnClickListener, ViewPager.OnPageChangeListener {

    private static final float ZERO = 0.0f;

    private final TextPaint textPaint = new TextPaint();

    private ConstraintLayout parent;

    private AppCompatTextView[] tvTabs;

    private String[] tabs;

    private ViewPager viewPager;

    private View vIndicator;

    private DisplayMetrics metrics;

    private int indicatorWidth;

    private int indicatorHeight;

    private int currentIndex = 0;

    private int tabTextColor = Color.BLACK;

    private int tabSelectedTextColor = Color.RED;

    private int viewPagerScrollState = ViewPager.SCROLL_STATE_IDLE;

    /**
     * 记录滑动起始的index
     */
    private int scrollStartIndex;

    /**
     * 记录滑动结束的index
     */
    private int scrollEndIndex;

    private OnTabSelectedListener onTabSelectedListener;

    public TabsController(ConstraintLayout parent) {
        this.parent = parent;
        metrics = parent.getResources().getDisplayMetrics();
        indicatorWidth = 20 * metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT;
        indicatorHeight = 2 * metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT;
    }

    public void setupViewPager(ViewPager viewPager) {
        this.viewPager = viewPager;
        this.viewPager.addOnPageChangeListener(this);
    }

    /**
     * 请在post中调用,因为post中才能获取measureWidth
     *
     * @param tabs
     */
    public void updateTabsView(String[] tabs) {
        if (tabs == null || tabs.length <= 0) {
            return;
        }
        if (tvTabs != null) {
            for (AppCompatTextView tvTab : tvTabs) {
                parent.removeView(tvTab);
            }
        }
        this.tabs = tabs;
        int totalWidth = parent.getMeasuredWidth();
        int length = tabs.length;
        tvTabs = new AppCompatTextView[length];
        float textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, metrics);
        if (length >= 6) {
            textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 14, metrics);
        }
        textPaint.setTextSize(textSize);
        int[] width = new int[length];
        int textWidth = 0;
        for (int i = 0; i < length; i++) {
            width[i] = (int) textPaint.measureText(tabs[i]);
            textWidth += width[i];
        }
        int padding = (totalWidth - textWidth) / length;
        for (int i = 0; i < length; i++) {
            width[i] = width[i] + padding;
        }
        int tabVerticalPadding = 10 * metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT;
        //添加tab
        for (int i = 0; i < length; i++) {
            int id = i + 1;
            tvTabs[i] = new AppCompatTextView(parent.getContext());
            tvTabs[i].setId(id);
            tvTabs[i].setText(tabs[i]);
            tvTabs[i].setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
            tvTabs[i].setTextColor(i == currentIndex ? tabSelectedTextColor : tabTextColor);
            tvTabs[i].setGravity(Gravity.CENTER);
            tvTabs[i].setPadding(0, tabVerticalPadding, 0, tabVerticalPadding);
            tvTabs[i].setOnClickListener(this);
            ConstraintLayout.LayoutParams params = new ConstraintLayout.LayoutParams(width[i], ViewGroup.LayoutParams.WRAP_CONTENT);
            if (i == 0) {
                params.leftToLeft = ConstraintLayout.LayoutParams.PARENT_ID;
                params.topToTop = ConstraintLayout.LayoutParams.PARENT_ID;
                //使用PACKED为了让整个tab水平居中,避免计算宽度时出现的误差
                params.horizontalChainStyle = ConstraintLayout.LayoutParams.CHAIN_PACKED;
                params.rightToLeft = id + 1;
            } else if (i == length - 1) {
                params.rightToRight = ConstraintLayout.LayoutParams.PARENT_ID;
                params.topToTop = ConstraintLayout.LayoutParams.PARENT_ID;
                params.leftToRight = id - 1;
            } else {
                params.topToTop = ConstraintLayout.LayoutParams.PARENT_ID;
                params.leftToRight = id - 1;
                params.rightToLeft = id + 1;
            }
            parent.addView(tvTabs[i], params);
        }
        //添加indicator
        if (vIndicator == null) {
            vIndicator = new View(parent.getContext());
            vIndicator.setBackgroundColor(Color.RED);
            ConstraintLayout.LayoutParams params = new ConstraintLayout.LayoutParams(indicatorWidth, indicatorHeight);
            params.bottomToBottom = tvTabs[0].getId();
            params.leftToLeft = ConstraintLayout.LayoutParams.PARENT_ID;
            parent.addView(vIndicator, params);
        }
        parent.post(new Runnable() {
            @Override
            public void run() {
                scrollIndicatorTo(0, 0);
            }
        });
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        int position = id - 1;
        if (onTabSelectedListener != null && !onTabSelectedListener.checkTabSelected(position)) {
            return;
        }
        if (position == currentIndex - 1 || position == currentIndex + 1) {
            if (viewPager != null) {
                //更新ViewPager,设置有滑动,在onPageScrolled的滑动indicator,在onPageSelected中调用setSelected
                viewPager.setCurrentItem(position, true);
            } else {
                setSelected(position);
            }
        } else {
            scrollIndicatorTo(position, 250);
            if (viewPager != null) {
                //跨度过大的,不使用自带的滑动效果
                viewPager.setCurrentItem(position, false);
            } else {
                setSelected(position);
            }
        }
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        Log.i("ViewPager", "onPageScrolled position: " + position + ", " + positionOffset);
        if (ViewPager.SCROLL_STATE_SETTLING == viewPagerScrollState) {
            //自动滑动至目标页面
            if (scrollStartIndex < scrollEndIndex) {
                //从index到index+n(n>0),position>=scrollStartIndex&&position<=scrollEndIndex
                scrollIndicator(position, position + 1, positionOffset);
            } else if (scrollStartIndex == scrollEndIndex) {
                //未发生变化,position=scrollStartIndex或者position=scrollStartIndex-1
                //与ViewPager.SCROLL_STATE_DRAGGING的场景操作相反
                if (position == scrollStartIndex) {
                    //position==scrollStartIndex,从index + 1到index,滑动至最初的位置即viewPager.getCurrentItem
                    scrollIndicator(position + 1, position, positionOffset);
                } else {
                    //position==scrollStartIndex,从index - 1到index,滑动至最初的位置即viewPager.getCurrentItem
                    scrollIndicator(position, position + 1, positionOffset);
                }
            } else {
                //从index到index-n(n>0),position>=scrollEndIndex&&position<scrollStartIndex
                scrollIndicator(position + 1, position, positionOffset);
            }
            return;
        }
        //剩下的场景只有: ViewPager.SCROLL_STATE_DRAGGING
        if (position == viewPager.getCurrentItem()) {
            //position==viewPager.getCurrentItem(),从index到index+1
            scrollIndicator(position, position + 1, positionOffset);
        } else {
            //position==viewPager.getCurrentItem() - 1,从index到index-1
            scrollIndicator(position + 1, position, positionOffset);
        }
    }

    @Override
    public void onPageSelected(int position) {
        //首次设置Adapter并不会触发onPageSelected
        Log.i("ViewPager", "onPageSelected current:" + currentIndex + ", target: " + position);
        //setSelected已经更新了currentIndex,所以在onPageScrolled中,不能使用currentIndex作为起始位置
        setSelected(position);
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        Log.d("ViewPager", "onPageScrollStateChanged current: " + currentIndex + ", viewPager.current: " + viewPager.getCurrentItem() + ", state: " + state);
        if (ViewPager.SCROLL_STATE_DRAGGING == viewPagerScrollState) {
            //手势滑动
        }
        if (ViewPager.SCROLL_STATE_SETTLING == state) {
            scrollStartIndex = currentIndex;
            scrollEndIndex = viewPager.getCurrentItem();
        }
        if (ViewPager.SCROLL_STATE_IDLE == state) {
            //滑动至空闲时,进行复位,避免通过onPageScrolled的positionOffset进行计算位置出现的误差
            scrollIndicatorTo(currentIndex, 0);
        }
        viewPagerScrollState = state;
    }


    /**
     * 滑动线
     * scrollNext是true,distanceRatio变化规律为：[0->1);
     * scrollNext是false,distanceRatio变化规律为：(1->0];
     *
     * @param scrollStartIndex
     * @param scrollEndIndex
     * @param distanceRatio
     */
    public void scrollIndicator(int scrollStartIndex, int scrollEndIndex, float distanceRatio) {
        if (Float.compare(distanceRatio, ZERO) <= 0) {
            return;
        }
        int count = getTabCount();
        if (scrollStartIndex < 0 || scrollStartIndex >= count
                || scrollEndIndex < 0 || scrollEndIndex >= count) {
            return;
        }
        float start = vIndicator.getX();
        float end;
        float startX = getIndicatorX(scrollStartIndex);
        float endX = getIndicatorX(scrollEndIndex);
        if (startX < endX) {
            //从index滑至index+1
            end = startX + (endX - startX) * distanceRatio;
            if (end > endX) {
                end = endX;
            }
        } else {
            //从index滑至index-1
            end = startX - (startX - endX) * (1 - distanceRatio);
            if (end < endX) {
                end = endX;
            }
        }
        //此处不使用动画是考虑,滑动的实时性
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(vIndicator, "x", start, end);
        objectAnimator.setDuration(0);
        objectAnimator.start();
    }

    /**
     * 滑动线
     *
     * @param index
     */
    public void scrollIndicatorTo(int index, long duration) {
        float start = vIndicator.getX();
        float end = getIndicatorX(index);
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(vIndicator, "x", start, end);
        objectAnimator.setDuration(duration);
        objectAnimator.start();
    }

    /**
     * @param index
     * @return
     */
    public float getIndicatorX(int index) {
        float x = tvTabs[0].getX();
        for (int i = 0; i < index; i++) {
            x += tvTabs[i].getMeasuredWidth();
        }
        x += (tvTabs[index].getMeasuredWidth() - indicatorWidth) / 2f;
        return x;
    }

    /**
     * @return
     */
    public int getTabCount() {
        return tvTabs != null ? tvTabs.length : 0;
    }


    /**
     * 设置选中
     *
     * @param index
     */
    public void setSelected(int index) {
        if (tvTabs == null || tvTabs.length <= 0) {
            return;
        }
        int count = tvTabs.length;
        if (index < 0 || index >= count || index == currentIndex) {
            return;
        }
        AppCompatTextView tvCurrent = tvTabs[currentIndex];
        tvCurrent.setTextColor(tabTextColor);

        AppCompatTextView tvNext = tvTabs[index];
        tvNext.setTextColor(tabSelectedTextColor);
        currentIndex = index;
    }


    public interface OnTabSelectedListener {

        /**
         * 点击index+1的tab时,根据业务需求判断是可选中
         *
         * @param index
         * @return true-表示可以选中,false-表示不可以选中
         */
        boolean checkTabSelected(int index);

        /**
         * 当index+1的tab被选中
         *
         * @param index
         */
        void onTabSelected(int index);
    }

    public void setOnTabSelectedListener(OnTabSelectedListener onTabSelectedListener) {
        this.onTabSelectedListener = onTabSelectedListener;
    }
}
